Popular Searches
Popular Course Categories
Popular Courses

Named Routes in Flutter

Flutter Navigation & Screens

Named Routes in Flutter

Named Routes in Flutter provide a way to navigate between screens using unique string-based route names such as /home, /login, /profile, and /settings. Instead of creating a MaterialPageRoute every time, routes can be registered centrally in MaterialApp and opened using Navigator.pushNamed().

Important: Flutter's current documentation states that named routes are no longer recommended for most new applications. For simple navigation, Navigator with MaterialPageRoute can be used, while applications with more advanced routing and deep-linking requirements can use go_router or another routing solution. Named routes are still useful for learning navigation and understanding existing Flutter applications.


1. What Are Named Routes?

A named route is a screen associated with a unique string identifier. For example:

  • / → Home screen
  • /login → Login screen
  • /profile → Profile screen
  • /settings → Settings screen
  • /about → About screen

Instead of writing a complete route every time, you can simply write:

Navigator.pushNamed(context, '/profile');

The route name is looked up in the application's routing table and the corresponding screen is created.


2. Why Use Named Routes?

  • Centralizes route definitions.
  • Makes navigation code shorter.
  • Provides consistent route names throughout an application.
  • Can be useful when many parts of an application navigate to the same screen.
  • Can pass arguments to screens.
  • Supports route replacement and route-stack operations.
  • Helps developers understand routing in existing Flutter projects.

3. Named Routes and Navigator

Flutter's Navigator manages a stack of routes. A route can be pushed onto the stack when opening a new screen and popped when closing the current screen.

Home
  ↓ pushNamed('/profile')
Profile
  ↓ pop()
Home

Navigator.pushNamed() pushes a named route onto the Navigator stack, while Navigator.pop() removes the current route.


4. Basic Named Route Syntax

Navigator.pushNamed(context, '/profile');

The first parameter is the current BuildContext, and the second parameter is the registered route name.


5. Creating Named Routes with MaterialApp

Named routes are commonly defined using the routes property of MaterialApp.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: {
        '/': (context) => const HomeScreen(),
        '/profile': (context) => const ProfileScreen(),
        '/settings': (context) => const SettingsScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pushNamed(context, '/profile');
          },
          child: const Text('Open Profile'),
        ),
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Go Back'),
        ),
      ),
    );
  }
}

class SettingsScreen extends StatelessWidget {
  const SettingsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Settings'),
      ),
      body: const Center(
        child: Text('Settings Screen'),
      ),
    );
  }
}

6. Understanding the routes Property

The routes property accepts a map where the key is the route name and the value is a widget builder.

routes: {
  '/': (context) => const HomeScreen(),
  '/profile': (context) => const ProfileScreen(),
  '/settings': (context) => const SettingsScreen(),
}

Conceptually:

Route NameScreen
/HomeScreen
/profileProfileScreen
/settingsSettingsScreen

7. initialRoute

The initialRoute property determines which named route should be displayed when the application starts.

MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => const HomeScreen(),
    '/login': (context) => const LoginScreen(),
    '/profile': (context) => const ProfileScreen(),
  },
);

In this example, the application starts with the / route.


8. Navigating to Another Screen

Use Navigator.pushNamed() to open a registered named route.

ElevatedButton(
  onPressed: () {
    Navigator.pushNamed(context, '/profile');
  },
  child: const Text('Open Profile'),
)

The Navigator searches for the /profile route and opens the corresponding screen.


9. Closing a Named Route

A named route can be closed using Navigator.pop().

ElevatedButton(
  onPressed: () {
    Navigator.pop(context);
  },
  child: const Text('Back'),
)

The current route is removed from the Navigator stack and the previous route becomes visible.


10. Navigating Between Multiple Named Routes

Consider an application containing Home, Products, Cart, and Profile screens.

MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => const HomeScreen(),
    '/products': (context) => const ProductsScreen(),
    '/cart': (context) => const CartScreen(),
    '/profile': (context) => const ProfileScreen(),
  },
);

Navigation can then be performed from different screens:

Navigator.pushNamed(context, '/products');

Navigator.pushNamed(context, '/cart');

Navigator.pushNamed(context, '/profile');

11. Complete Multi-Screen Example

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: {
        '/': (context) => const HomeScreen(),
        '/about': (context) => const AboutScreen(),
        '/contact': (context) => const ContactScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () {
              Navigator.pushNamed(context, '/about');
            },
            child: const Text('About'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.pushNamed(context, '/contact');
            },
            child: const Text('Contact'),
          ),
        ],
      ),
    );
  }
}

class AboutScreen extends StatelessWidget {
  const AboutScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('About')),
      body: const Center(
        child: Text('About Screen'),
      ),
    );
  }
}

class ContactScreen extends StatelessWidget {
  const ContactScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Contact')),
      body: const Center(
        child: Text('Contact Screen'),
      ),
    );
  }
}

12. Named Route Constants

Writing route names as strings throughout a large project can cause spelling mistakes. A common approach is to store route names in constants.

class AppRoutes {
  static const String home = '/';
  static const String login = '/login';
  static const String profile = '/profile';
  static const String settings = '/settings';
}

Register the routes:

MaterialApp(
  routes: {
    AppRoutes.home: (context) => const HomeScreen(),
    AppRoutes.login: (context) => const LoginScreen(),
    AppRoutes.profile: (context) => const ProfileScreen(),
    AppRoutes.settings: (context) => const SettingsScreen(),
  },
);

Navigate using the constants:

Navigator.pushNamed(context, AppRoutes.profile);

This reduces the chance of accidentally typing different route names in different parts of the application.


13. Passing Arguments to Named Routes

Navigator.pushNamed() supports an optional arguments parameter. This allows data to be passed to the destination route.

Navigator.pushNamed(
  context,
  '/profile',
  arguments: {
    'name': 'Rahul',
    'age': 25,
  },
);

The arguments are associated with the route through RouteSettings.arguments.


14. Reading Arguments with ModalRoute

The destination screen can access arguments using ModalRoute.of(context).

class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final arguments =
        ModalRoute.of(context)!.settings.arguments as Map;

    final String name = arguments['name'];
    final int age = arguments['age'];

    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
      body: Center(
        child: Text(
          'Name: $name\nAge: $age',
          textAlign: TextAlign.center,
        ),
      ),
    );
  }
}

15. Passing a Custom Object

Instead of passing a Map, you can pass a custom Dart object.

class User {
  final String name;
  final String email;

  User({
    required this.name,
    required this.email,
  });
}

Pass the object:

final user = User(
  name: 'Amit',
  email: '[email protected]',
);

Navigator.pushNamed(
  context,
  '/profile',
  arguments: user,
);

Read it on the destination screen:

final user = ModalRoute.of(context)!.settings.arguments as User;

Text(user.name);
Text(user.email);

16. Passing Arguments Using onGenerateRoute

onGenerateRoute provides more control over how routes are created and is useful when route creation depends on arguments or route names.

MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == '/profile') {
      final user = settings.arguments as User;

      return MaterialPageRoute(
        builder: (context) {
          return ProfileScreen(user: user);
        },
      );
    }

    return MaterialPageRoute(
      builder: (context) => const HomeScreen(),
    );
  },
);

Navigation:

Navigator.pushNamed(
  context,
  '/profile',
  arguments: User(
    name: 'Amit',
    email: '[email protected]',
  ),
);

17. What is onGenerateRoute?

onGenerateRoute is a callback used to create routes dynamically when a route is requested. It receives RouteSettings, which contains information such as the requested route name and arguments.

onGenerateRoute: (settings) {
  print(settings.name);
  print(settings.arguments);

  return MaterialPageRoute(
    builder: (context) => const HomeScreen(),
  );
}

It can be useful when an application has many routes or needs custom route-generation logic.


18. Handling Unknown Routes

You can provide onUnknownRoute to display a fallback screen when a requested route cannot be resolved.

MaterialApp(
  routes: {
    '/': (context) => const HomeScreen(),
    '/profile': (context) => const ProfileScreen(),
  },
  onUnknownRoute: (settings) {
    return MaterialPageRoute(
      builder: (context) => const NotFoundScreen(),
    );
  },
);

For example, if the application tries to navigate to an unavailable route:

Navigator.pushNamed(context, '/something-that-does-not-exist');

The application can display the NotFoundScreen instead of leaving the user without an appropriate destination.


19. pushReplacementNamed()

pushReplacementNamed() replaces the current route with another named route.

This is particularly useful after login or registration.

Navigator.pushReplacementNamed(
  context,
  '/dashboard',
);

Example login flow:

ElevatedButton(
  onPressed: () {
    Navigator.pushReplacementNamed(
      context,
      '/dashboard',
    );
  },
  child: const Text('Login'),
)

After reaching the dashboard, pressing the back button does not return to the login screen because the login route was replaced.


20. pushNamedAndRemoveUntil()

This method pushes a named route and removes previous routes according to a predicate.

A common example is logging out and returning to the login screen while removing previous application screens.

Navigator.pushNamedAndRemoveUntil(
  context,
  '/login',
  (route) => false,
);

This clears the existing Navigator stack and leaves the login route as the active route.


21. popAndPushNamed()

popAndPushNamed() removes the current route and pushes another named route.

Navigator.popAndPushNamed(
  context,
  '/settings',
);

This can be useful when the current screen should be replaced by another screen in a single navigation operation.


22. Named Routes with Login and Dashboard

A typical application can define login and dashboard routes like this:

MaterialApp(
  initialRoute: '/login',
  routes: {
    '/login': (context) => const LoginScreen(),
    '/dashboard': (context) => const DashboardScreen(),
    '/profile': (context) => const ProfileScreen(),
  },
);

After successful authentication:

Navigator.pushReplacementNamed(
  context,
  '/dashboard',
);

From the dashboard:

Navigator.pushNamed(
  context,
  '/profile',
);

23. Named Routes in an E-Commerce App

Imagine an e-commerce application with these routes:

RoutePurpose
/Home
/productsProduct list
/product-detailsProduct details
/cartShopping cart
/checkoutCheckout
/order-successOrder confirmation

The route table might look like:

routes: {
  '/': (context) => const HomeScreen(),
  '/products': (context) => const ProductsScreen(),
  '/product-details': (context) => const ProductDetailsScreen(),
  '/cart': (context) => const CartScreen(),
  '/checkout': (context) => const CheckoutScreen(),
  '/order-success': (context) => const OrderSuccessScreen(),
}

Opening the cart:

Navigator.pushNamed(context, '/cart');

Opening checkout:

Navigator.pushNamed(context, '/checkout');

After successful payment:

Navigator.pushNamedAndRemoveUntil(
  context,
  '/order-success',
  (route) => false,
);

24. Named Routes vs Direct Navigator.push()

FeatureNamed RoutesDirect Route
NavigationpushNamed()push()
Route identifierString nameRoute object
Central route tableUsually usedNot required
ArgumentsSupportedSupported directly through constructors
Simple navigationWorksWorks
Large/complex routingLimitedCan become manual

Direct navigation example:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ProfileScreen(),
  ),
);

Named route example:

Navigator.pushNamed(
  context,
  '/profile',
);

25. Important Current Flutter Recommendation

Flutter's current navigation documentation does not recommend named routes for most new applications. Named routes have limitations, especially for advanced deep linking and browser history behavior. For simple applications, Navigator with MaterialPageRoute is an option. For applications requiring advanced routing, deep linking, or more sophisticated navigation configuration, Flutter recommends using a routing solution such as go_router.

However, named routes remain important for learning Flutter navigation and for maintaining or understanding applications that already use them.


26. Named Routes and Deep Linking

A deep link is a URL or external link that opens a specific location inside an application. Flutter supports deep linking on Android, iOS, and the web.

Named routes can be used for basic route-based navigation, but they have limitations for advanced deep-link behavior. For modern applications with complex deep linking, a Router-based solution or routing package such as go_router is generally more appropriate.


27. Named Routes with Bottom Navigation

Named routes can also be triggered from navigation controls.

NavigationBar(
  selectedIndex: 0,
  onDestinationSelected: (index) {
    if (index == 0) {
      Navigator.pushNamed(context, '/home');
    } else if (index == 1) {
      Navigator.pushNamed(context, '/profile');
    } else if (index == 2) {
      Navigator.pushNamed(context, '/settings');
    }
  },
  destinations: const [
    NavigationDestination(
      icon: Icon(Icons.home),
      label: 'Home',
    ),
    NavigationDestination(
      icon: Icon(Icons.person),
      label: 'Profile',
    ),
    NavigationDestination(
      icon: Icon(Icons.settings),
      label: 'Settings',
    ),
  ],
)

28. Common Mistakes with Named Routes

Mistake 1: Route Name Typo

Navigator.pushNamed(context, '/profle');

If the registered route is /profile, the typo can cause route resolution problems.

Mistake 2: Forgetting to Register a Route

Navigator.pushNamed(context, '/settings');

But if /settings is not defined in the route configuration and no suitable route-generation handler exists, the route cannot be resolved.

Mistake 3: Incorrect Argument Type

final user = ModalRoute.of(context)!.settings.arguments as User;

If a different object type is passed, the cast can fail at runtime.

Mistake 4: Using Named Routes for Complex Routing Without Considering Their Limitations

For applications requiring sophisticated deep linking, browser history behavior, nested navigation, or complex route configuration, consider a Router-based approach or a routing package.


29. Best Practices

  • Use meaningful route names such as /profile and /settings.
  • Keep route names consistent throughout the application.
  • Consider using constants instead of repeatedly typing route strings.
  • Use custom objects instead of large unstructured Maps when passing complex data.
  • Validate route arguments before using them.
  • Use pushReplacementNamed() when the previous screen should not remain in the navigation stack.
  • Use pushNamedAndRemoveUntil() when an entire navigation history needs to be cleared.
  • Use onGenerateRoute when dynamic route creation is needed.
  • Use onUnknownRoute for a fallback destination where appropriate.
  • For new applications with complex navigation requirements, evaluate modern routing solutions such as go_router.

30. Quick Revision

ConceptCodePurpose
Define routeroutes: {}Register named routes
Start routeinitialRouteChoose initial named route
Open routepushNamed()Open a named screen
Close routepop()Return to previous screen
Pass dataarguments:Send data to destination
Read dataModalRoute.of()Access route arguments
Dynamic routingonGenerateRouteCreate routes dynamically
FallbackonUnknownRouteHandle unresolved routes
Replace routepushReplacementNamed()Replace current route
Clear stackpushNamedAndRemoveUntil()Remove previous routes
Pop and pushpopAndPushNamed()Replace current route with named route

31. Interview Questions

Q1. What are named routes in Flutter?

Named routes are routes identified by string names and registered in the application's navigation configuration.

Q2. Which method is used to open a named route?

Navigator.pushNamed().

Q3. How do you close the current screen?

Use Navigator.pop(context).

Q4. How do you define named routes?

They can be registered using the routes property of MaterialApp or generated dynamically with route-generation callbacks.

Q5. How can data be passed to a named route?

Use the arguments parameter of Navigator.pushNamed().

Q6. How can named route arguments be accessed?

They can be accessed using ModalRoute.of(context)!.settings.arguments or handled inside onGenerateRoute.

Q7. What is the difference between pushNamed and pushReplacementNamed?

pushNamed() adds a new route to the navigation stack, while pushReplacementNamed() replaces the current route with the new named route.

Q8. What is onGenerateRoute?

onGenerateRoute is a callback that can dynamically create a route based on route settings such as the requested route name and arguments.

Q9. Are named routes recommended for all new Flutter applications?

No. Flutter's current documentation says named routes are no longer recommended for most applications. For simple navigation, Navigator with MaterialPageRoute can be used, while more advanced applications can use a routing package such as go_router.


32. Practice Exercise

Create a Flutter application with the following named routes:

  • / → Home Screen
  • /login → Login Screen
  • /register → Register Screen
  • /dashboard → Dashboard Screen
  • /profile → Profile Screen
  • /settings → Settings Screen

Implement the following navigation flow:

Login
  ↓
Dashboard
  ↓
Profile
  ↓
Settings

Also practice:

  1. Passing a username to the Profile screen.
  2. Replacing Login with Dashboard after successful login.
  3. Returning from Profile to Dashboard.
  4. Clearing the navigation stack after logout.
  5. Creating an unknown-route fallback screen.

33. Key Takeaways

  • Named routes provide string-based navigation between Flutter screens.
  • Routes can be registered using the routes property of MaterialApp.
  • Navigator.pushNamed() opens a named route.
  • Navigator.pop() closes the current route.
  • initialRoute can specify the starting named route.
  • The arguments parameter can be used to pass data.
  • ModalRoute.of(context) can retrieve route arguments.
  • onGenerateRoute supports dynamic route creation.
  • pushReplacementNamed() is useful for flows such as login to dashboard.
  • pushNamedAndRemoveUntil() can clear previous routes.
  • Named routes are useful for learning and existing applications, but Flutter currently recommends other approaches for most new applications.
  • For advanced navigation and deep linking, consider Router-based navigation or go_router.

34. Official Flutter Resources


35. Learn Flutter with JustAcademy

To learn Flutter development, Dart programming, widgets, navigation, state management, APIs, Firebase integration, and practical application development, explore the following resources:

JustAcademy Flutter Training Course

Register for Flutter Course Demo

whatsapp